package com.yycx.msg.provider.service.impl;

import cn.hutool.core.map.MapUtil;
import com.yycx.common.base.entity.EntityMap;
import com.yycx.common.base.utils.FlymeUtils;
import com.yycx.common.constants.CommonConstants;
import com.yycx.common.mybatis.base.service.impl.BaseServiceImpl;
import com.yycx.common.mybatis.model.ResultBody;
import com.yycx.common.mybatis.query.CriteriaDelete;
import com.yycx.common.mybatis.query.CriteriaQuery;
import com.yycx.common.mybatis.query.CriteriaSave;
import com.yycx.common.mybatis.query.CriteriaUpdate;
import com.yycx.common.security.OpenHelper;
import com.yycx.common.utils.DateUtils;
import com.yycx.msg.client.entity.MsgContent;
import com.yycx.msg.client.entity.MsgReceive;
import com.yycx.msg.client.entity.MsgType;
import com.yycx.msg.client.enums.MsgTypeEnum;
import com.yycx.msg.provider.mapper.MsgReceiveMapper;
import com.yycx.msg.provider.service.MsgContentService;
import com.yycx.msg.provider.service.MsgReceiveService;
import com.yycx.msg.provider.service.MsgTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 消息接收表接口实现类
 *
 * @author flyme
 * @date 2020-02-28
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MsgReceiveServiceImpl extends BaseServiceImpl<MsgReceiveMapper, MsgReceive> implements MsgReceiveService {
    @Resource
    private MsgContentService msgContentService;

    @Autowired
    private MsgTypeService msgTypeService;

    @Override
    public ResultBody beforeAdd(CriteriaSave cs, MsgReceive receive, EntityMap extra) {
        return ResultBody.ok();
    }


    @Override
    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public ResultBody beforePageList(CriteriaQuery<MsgReceive> cq, MsgReceive receive, EntityMap requestMap) {
        Long userId = commonBeanUtils.getUserId();
        initUserMsg(userId);
        cq.select(MsgReceive.class, "msgUserId", "readState", "createTime");
        cq.select(MsgType.class, "typeName");
        cq.select(MsgContent.class, "msgId", "msgTitle", "msgImage", "msgContent", "sendTime");
        cq.eq(MsgReceive.class, "receiveUserId", userId);
        cq.eq(MsgReceive.class, "deleted", CommonConstants.DEL_NO);
        cq.eq(MsgType.class, "typeCode");
        cq.like(MsgContent.class, "msgTitle");
        cq.createJoin(MsgContent.class);
        cq.createJoin(MsgType.class).setMainAlias("content").setMainField("msgTypeId").setJoinField("msgTypeId");
        cq.orderByDesc("receive.createTime");
        return ResultBody.ok();
    }

    @Override
    public void afterGet(CriteriaQuery cq, EntityMap result) {
        Long msgId = MapUtil.getLong(result, "msgId");
        Long msgUserId = MapUtil.getLong(result, "msgUserId");
        updatReadState(msgUserId);
        EntityMap content = msgContentService.findById(msgId);
        if (FlymeUtils.isNotEmpty(content)) {
            result.putAll(content);
        }
    }

    /**
     * 根据主键更新消息读取状态
     *
     * @param msgUserId 主键值
     * @return
     */
    private void updatReadState(Long msgUserId) {
        CriteriaUpdate<MsgReceive> cu = new CriteriaUpdate();
        cu.lambda().set(true, MsgReceive::getReadState, CommonConstants.ENABLED).eq(true, MsgReceive::getMsgUserId, msgUserId);
        update(cu);
    }

    /**
     * 更新用户消息全部设置为已读
     * 默认当前登录用户,也可以传递userId指定用户
     *
     * @return
     */
    public void updateAllReadState() {
        Long userId = commonBeanUtils.getUserId();
        if (FlymeUtils.isNotEmpty(userId)) {
            CriteriaUpdate<MsgReceive> cu = new CriteriaUpdate();
            cu.lambda().set(true, MsgReceive::getReadState, CommonConstants.ENABLED).eq(true, MsgReceive::getReceiveUserId, userId);
            update(cu);
        }
    }

    /**
     * 清空用户已读消息
     * 默认当前登录用户,也可以传递userId指定用户
     *
     * @return
     */
    public void deleteAllRead() {
        Long userId = commonBeanUtils.getUserId();
        if (FlymeUtils.isNotEmpty(userId)) {
            //删除推送消息
            deletePushMsg(userId);
            //删除推送本体消息
            msgContentService.deleteUserMsgByTypeId(userId, MsgTypeEnum.PushMsg.getValue());
            //删除个人消息(更新删除状态)
            deleteAllUserMsg(userId);
        }
    }

    /**
     * 删除推送类型消息
     *
     * @param userId
     */
    public void deletePushMsg(Long userId) {
        CriteriaDelete cd = new CriteriaDelete();
        cd.eq(true, "msgTypeId", MsgTypeEnum.PushMsg.getValue());
        cd.eq(true, "receiveUserId", userId);
        remove(cd);
    }

    /**
     * 删除其他类型消息
     *
     * @param userId
     */
    public void deleteAllUserMsg(Long userId) {
        CriteriaUpdate<MsgReceive> cu = new CriteriaUpdate();
        cu.lambda().set(true, MsgReceive::getDeleted, CommonConstants.DEL_YES).eq(true, MsgReceive::getReceiveUserId, userId);
        update(cu);
    }


    public Boolean deleteByMsgId(Serializable[] msgIds) {
        CriteriaDelete cd = new CriteriaDelete();
        cd.in(true, "msgId", msgIds);
        return remove(cd);
    }


    @Override
    public Long countNoRead() {
        Long userId = commonBeanUtils.getUserId();
        initUserMsg(userId);
        CriteriaQuery cq = new CriteriaQuery(MsgReceive.class);
        cq.eq(true, "receiveUserId", userId);
        cq.eq("readState", CommonConstants.DISABLED);
        return count(cq);
    }

    @Override
    public List<EntityMap> selectNoReadMessage(Long userId, String typeCode) {
        return selectNoReadMessage(userId, typeCode, 0);
    }

    public List<EntityMap> selectNoReadMessage(Long userId, Long companyId, String typeCode, Integer limit) {
        List<EntityMap> reuslt = new ArrayList<>();
        if (FlymeUtils.isNotEmpty(userId)) {
            MsgType msgType = msgTypeService.findByTypeCode(typeCode);
            CriteriaQuery<MsgReceive> cq = new CriteriaQuery(MsgReceive.class);
            cq.select(MsgReceive.class,"msgUserId id");
            cq.select(MsgContent.class,"msgTitle title","msgDescribe description");
            cq.and(e -> e.eq(true, "receiveUserId", userId).or().eq(true, "receiveUserId", companyId));
            cq.eq("readState", CommonConstants.DISABLED);
            cq.eq(MsgReceive.class,"deleted", CommonConstants.DEL_NO);
            cq.eq(true, "receive.msgTypeId", msgType.getMsgTypeId());
            cq.limit(limit);
            cq.createJoin(MsgContent.class).setMainField("msgId").setJoinField("msgId");
            reuslt = selectEntityMap(cq);
        }
        return reuslt;
    }

    public List<EntityMap> selectNoReadMessage(Long userId, String typeCode, Integer limit) {
        List<EntityMap> reuslt = new ArrayList<>();
        if (FlymeUtils.isNotEmpty(userId)) {
            MsgType msgType = msgTypeService.findByTypeCode(typeCode);
            CriteriaQuery cq = new CriteriaQuery(MsgReceive.class);
            cq.eq(true, "receiveUserId", userId);
            cq.eq("readState", CommonConstants.DISABLED);
            cq.eq(true, "receive.msgTypeId", msgType.getMsgTypeId());
            cq.limit(limit);
            cq.createJoin(MsgContent.class).setMainField("msgId").setJoinField("msgId");
            reuslt = selectEntityMap(cq);
        }
        return reuslt;
    }


    @Override
    public EntityMap selectLastNoReadMessage(Long userId, String typeCode) {
        EntityMap reuslt = new EntityMap();
        if (FlymeUtils.isNotEmpty(userId)) {
            MsgType msgType = msgTypeService.findByTypeCode(typeCode);
            CriteriaQuery cq = new CriteriaQuery(MsgReceive.class);
            cq.eq(true, "receiveUserId", userId);
            cq.eq("readState", CommonConstants.DISABLED);
            cq.eq(true, "receive.msgTypeId", msgType.getMsgTypeId());
            cq.createJoin(MsgContent.class).setMainField("msgId").setJoinField("msgId");
            cq.orderByDesc("content.createTime");
            cq.last("limit 1");
            List<EntityMap> list = selectEntityMap(cq);
            if (FlymeUtils.isNotEmpty(list)) {
                reuslt = list.get(0);
            }
        }
        return reuslt;
    }

    @Override
    public Integer countNoReadMessage(String typeCode) {
        MsgType msgType = msgTypeService.findByTypeCode(typeCode);
        Long msgTypeId = msgType.getMsgTypeId();
        return countNoReadMessage(msgTypeId);
    }

    @Override
    public Integer countNoReadMessage(Long msgTypeId) {
        Long userId = commonBeanUtils.getUserId();
        if (FlymeUtils.isNotEmpty(userId)) {
            initUserMsg(userId);
            CriteriaQuery cq = new CriteriaQuery(MsgReceive.class);
            cq.addSelect("count(*)");
            cq.eq("readState", CommonConstants.DISABLED);
            cq.eq(true, "receiveUserId", userId);
            cq.eq(true, "receive.msgTypeId", msgTypeId);
            cq.createJoin(MsgContent.class).setMainField("msgId").setJoinField("msgId");
            return baseMapper.countNoReadMessage(cq);
        }
        return 0;
    }

    @Override
    public ResultBody getAllNoReadMessageNum(Long userId) {
        EntityMap entityMap = new EntityMap();
        Long noReadNum = 0L;
        if (FlymeUtils.isNotEmpty(userId)) {
            noReadNum = countNoRead();
        }
        entityMap.put("noReadNum", noReadNum);
        return ResultBody.ok(entityMap);
    }

    @Override
    public List<EntityMap> getNoticeList() {
        Long userId = commonBeanUtils.getUserId();
        Long companyId = commonBeanUtils.getCompanyId();
        //TODO 待优化有消息时才初始化
        initUserMsg(userId);
        List<MsgType> typeList = msgTypeService.selectByGroup(1);
        List<EntityMap> result = new ArrayList<>();
        if (FlymeUtils.isNotEmpty(typeList)) {
            for (MsgType msgType : typeList) {
                EntityMap typeData = new EntityMap();
                typeData.put("key", msgType.getTypeCode());
                typeData.put("typeTurnUrl", msgType.getTypeTurnUrl());
                typeData.put("name", msgType.getTypeName());
                List<EntityMap> list = selectNoReadMessage(userId, companyId, msgType.getTypeCode(), 10);
                typeData.put("list", list);
                result.add(typeData);
            }
        }
        return result;
    }

    @Override
    public MsgReceive sendMsgReceiveNotice(String typeCode, Long receiveUserId, String msgTitle, String content) {
        MsgType msgType = msgTypeService.findByTypeCode(typeCode);
        MsgContent msgContent = new MsgContent();
        msgContent.setMsgTypeId(msgType.getMsgTypeId());
        msgContent.setMsgTitle(msgTitle);
        msgContent.setMsgDescribe(msgTitle);
        msgContent.setMsgContent(content);
        msgContent.setDeleted(CommonConstants.DEL_NO);
        msgContent.setMsgState(CommonConstants.DISABLED);
        msgContent.setSendTime(DateUtils.getNowDateTime());
        boolean save = msgContentService.save(msgContent);
        MsgReceive msgReceive = new MsgReceive();
        if (save) {
            msgReceive.setMsgId(msgContent.getMsgId());
            msgReceive.setDeleted(CommonConstants.DEL_NO);
            msgReceive.setMsgTypeId(msgType.getMsgTypeId());
            msgReceive.setReadState(CommonConstants.DISABLED);
            msgReceive.setReceiveUserId(receiveUserId);
            save(msgReceive);
        }
        return msgReceive;
    }

    /**
     * 初始化用户消息
     */
    public void initUserMsg(Long userId) {
        if (FlymeUtils.isNotEmpty(userId)) {
            EntityMap params = new EntityMap();
            params.put("receiveUserId", userId);
            List<MsgContent> list = msgContentService.selectNotReceiveByUserId(params);
            if (FlymeUtils.isNotEmpty(list)) {
                List<MsgReceive> receiveList = new ArrayList<>();
                for (MsgContent msgContent : list) {
                    MsgReceive receive = new MsgReceive();
                    receive.setReceiveUserId(userId);
                    receive.setMsgTypeId(msgContent.getMsgTypeId());
                    receive.setDeleted(CommonConstants.DEL_NO);
                    receive.setReadState(CommonConstants.DISABLED);
                    receive.setMsgId(msgContent.getMsgId());
                    receiveList.add(receive);
                }
                saveBatch(receiveList);
            }
        }
    }
}
